package com.peng.netty_test;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.channel.*;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.util.concurrent.GlobalEventExecutor;

public class NettyServer {
    //管理连接进来的所有client实例， 可以在client通道关闭时自动从此集合中剔除。 并使用一个单线程在必要时进行指定的操作：eg：群发
    public static ChannelGroup clients = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);


    public static void main(String[] args) {
        EventLoopGroup bossGroup = new NioEventLoopGroup(1);
        EventLoopGroup workerGroup = new NioEventLoopGroup(5);

        ServerBootstrap bootstrap = new ServerBootstrap();

        try {
            ChannelFuture channelFuture = bootstrap.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .handler(new ChannelInitializer<NioServerSocketChannel>() { //accpetorhandler
                        @Override
                        protected void initChannel(NioServerSocketChannel ch) throws Exception {
                            System.out.println("handler=>initChannel");
                        }
                    })
                    .childHandler(new ChannelInitializer<SocketChannel>() { // clienthandler
                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            System.out.println("childHandler=>initChannel....");
                            ChannelPipeline pipeline = ch.pipeline();
                            pipeline.addLast(new ChannelInboundHandlerAdapter() {
                                @Override
                                public void channelActive(ChannelHandlerContext ctx) throws Exception {
                                    System.out.println("a client connected.....");
                                    clients.add(ctx.channel());
                                }

                                @Override
                                public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
                                    ByteBuf buf = (ByteBuf) msg;
                                    byte[] b = new byte[buf.readableBytes()];
                                    buf.getBytes(buf.readerIndex(), b);
                                    System.out.println(new String(b));
                                    System.out.println(buf.refCnt());
                                    //正常两个JAVA程序进行传输数据，需要将其中一个APP的数据从所在JVM中，复制一份到系统内存中，在通过系统内存去向外传输
                                    //不过这样存在一个问题就是，这块内存将不在JVM垃圾回收管理范畴之内
                                    // 类似像C++一样，需要手动进行回收这块内存，不然会造成内存泄露的问题。
                                    //  writeAndFlush会写完并释放这块内存
//                                    ctx.writeAndFlush(buf);//netty会直接把字节数组写到堆外内存，所以快
                                    clients.writeAndFlush(buf); // 群发给当前所有连接的client端
                                    //如果没有通过writeAndFlush，则需要手动释放这块内存，否则会产生内存泄漏
//                                    ReferenceCountUtil.release(buf);    //将引用计数减少1，并在引用计数为0时释放该对象
                                }

                                @Override
                                public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
                                    cause.printStackTrace();
                                    ctx.close(); //调用此client的通道的close方法
                                }
                            });
                        }
                    })
                    .bind(8888)
                    .sync();

            channelFuture.channel().closeFuture().sync();//阻塞，直到close方法被调用
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }

    }
}
